"""
Market data service for fetching and processing cryptocurrency data
"""

import ccxt
import pandas as pd
from datetime import datetime, timedelta
from typing import List, Optional, Dict, Any
import asyncio
import aiohttp

from app.core.config import settings
from app.models.market_data import KlineData
from app.core.database import SessionLocal


class MarketDataService:
    """Service for fetching and managing market data"""
    
    def __init__(self):
        self.exchanges = {
            'binance': ccxt.binance({
                'apiKey': settings.BINANCE_API_KEY,
                'secret': settings.BINANCE_SECRET_KEY,
                'enableRateLimit': True,
            }),
            'coinbase': ccxt.coinbase({
                'apiKey': settings.COINBASE_API_KEY,
                'secret': settings.COINBASE_SECRET_KEY,
                'enableRateLimit': True,
            })
        }
        
    async def fetch_klines(
        self,
        symbol: str,
        timeframe: str,
        limit: int = 500,
        exchange: str = 'binance'
    ) -> pd.DataFrame:
        """Fetch kline data from exchange"""
        try:
            exchange_client = self.exchanges[exchange]
            
            # Fetch OHLCV data
            ohlcv = await self._async_fetch_ohlcv(
                exchange_client, 
                symbol, 
                timeframe, 
                limit
            )
            
            # Convert to DataFrame
            df = pd.DataFrame(
                ohlcv,
                columns=[
                    'timestamp', 'open', 'high', 'low', 
                    'close', 'volume'
                ]
            )
            
            # Convert timestamp to datetime
            df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
            df['symbol'] = symbol
            df['timeframe'] = timeframe
            
            return df
            
        except Exception as e:
            raise Exception(f"Error fetching klines: {str(e)}")
    
    async def _async_fetch_ohlcv(
        self, 
        exchange, 
        symbol: str, 
        timeframe: str, 
        limit: int
    ) -> List[List[float]]:
        """Async wrapper for fetching OHLCV data"""
        loop = asyncio.get_event_loop()
        return await loop.run_in_executor(
            None, 
            exchange.fetch_ohlcv, 
            symbol, 
            timeframe, 
            None, 
            limit
        )
    
    def get_available_symbols(self, exchange: str = 'binance') -> List[str]:
        """Get list of available trading symbols"""
        try:
            exchange_client = self.exchanges[exchange]
            markets = exchange_client.load_markets()
            
            # Filter for USDT pairs
            usdt_pairs = [
                symbol for symbol in markets.keys() 
                if symbol.endswith('USDT') and 'UP' not in symbol and 'DOWN' not in symbol
            ]
            
            # Return top cryptocurrencies
            top_symbols = ['BTC/USDT', 'ETH/USDT', 'SOL/USDT', 'BNB/USDT', 
                          'XRP/USDT', 'ADA/USDT', 'DOGE/USDT', 'MATIC/USDT']
            
            return [s for s in top_symbols if s in usdt_pairs][:10]
            
        except Exception as e:
            raise Exception(f"Error fetching symbols: {str(e)}")
    
    def get_timeframes(self, exchange: str = 'binance') -> List[str]:
        """Get available timeframes"""
        try:
            exchange_client = self.exchanges[exchange]
            return list(exchange_client.timeframes.keys())
        except:
            return ['1m', '5m', '15m', '30m', '1h', '2h', '4h', '6h', '8h', '12h', '1d', '3d', '1w', '1M']
    
    async def save_klines_to_db(self, df: pd.DataFrame) -> bool:
        """Save kline data to database"""
        try:
            db = SessionLocal()
            
            for _, row in df.iterrows():
                kline = KlineData(
                    symbol=row['symbol'],
                    timeframe=row['timeframe'],
                    timestamp=row['timestamp'],
                    open_price=float(row['open']),
                    high_price=float(row['high']),
                    low_price=float(row['low']),
                    close_price=float(row['close']),
                    volume=float(row['volume'])
                )
                db.merge(kline)
            
            db.commit()
            db.close()
            return True
            
        except Exception as e:
            print(f"Error saving to DB: {str(e)}")
            return False
    
    async def get_latest_price(self, symbol: str, exchange: str = 'binance') -> Dict[str, float]:
        """Get latest price for a symbol"""
        try:
            exchange_client = self.exchanges[exchange]
            ticker = await self._async_fetch_ticker(exchange_client, symbol)
            
            return {
                'symbol': symbol,
                'price': ticker['last'],
                'bid': ticker['bid'],
                'ask': ticker['ask'],
                'volume': ticker['quoteVolume'],
                'change_24h': ticker['percentage'],
                'timestamp': datetime.now()
            }
            
        except Exception as e:
            raise Exception(f"Error fetching latest price: {str(e)}")
    
    async def _async_fetch_ticker(self, exchange, symbol: str) -> Dict[str, Any]:
        """Async wrapper for fetching ticker data"""
        loop = asyncio.get_event_loop()
        return await loop.run_in_executor(
            None, 
            exchange.fetch_ticker, 
            symbol
        )


# Global instance
market_data_service = MarketDataService()
